package com.ruoyi.lvlian.controller;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.openapi.sdk.service.DataExchangeService;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.web.controller.BaseController;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.redis.service.RedisService;
import com.ruoyi.lvlian.domain.Coordinate;
import com.ruoyi.lvlian.domain.MapLabel;
import com.ruoyi.lvlian.domain.TrackInfo;
import com.ruoyi.lvlian.domain.ZjVehicle;
import com.ruoyi.lvlian.dto.SinoiovDto;
import com.ruoyi.lvlian.enums.Color;
import com.ruoyi.lvlian.util.ColorMapping;
import com.ruoyi.lvlian.util.CoordinateConverter;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import com.ruoyi.common.core.utils.MD5Utils;

import java.util.*;
import java.util.stream.Collectors;


/**
 * 中交物流 测试接口
 */
@CrossOrigin //开放前端的跨域访问
@Api(value = "中交视图相关", tags = "中交视图相关接口")
@RestController
@RequestMapping("/sinoiov")
public class SinoiovController extends BaseController {

    private static final Logger log = LoggerFactory.getLogger(SinoiovController.class);


    @Value("${sinoiov_zhengshi.url}")
    private String url;
    @Value("${sinoiov_zhengshi.srt}")
    private String srt;
    @Value("${sinoiov_zhengshi.clientId}")
    private String clientId;
    private ObjectMapper objectMapper = new ObjectMapper();
    private Map<String, Integer> colorMap = ColorMapping.getColorMap();

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedisService redisService;


    /**
     * 运输行程服务1
     *
     * @param zjVehicle 车辆信息
     * @return http://localhost:8080/lvlian/sinoiov/routerPath
     * http://123.249.100.15:8080/lvlian/sinoiov/routerPath
     * http://123.249.100.15/dev-api/lvlian/sinoiov/routerPath
     * http://123.249.100.15:8082/sinoiov/routerPath
     * http://123.249.100.15:8082/sinoiov/routerPath
     * http://localhost:8082/sinoiov/routerPath
     */
    @ApiOperation("运输行程服务1查询车辆运行轨迹")
    @GetMapping("/routerPath")
    public AjaxResult routerPath(ZjVehicle zjVehicle) {
        if (StringUtils.isEmpty(zjVehicle.getVclN())) {
            return AjaxResult.error("车牌号码为空");
        }
        if (StringUtils.isEmpty(zjVehicle.getQryBtm())) {
            return AjaxResult.error("查询开始时间为空");
        }
        Map<String, String> map = new HashMap<String, String>(3);
        map.put("cid", clientId);
        map.put("srt", srt);
        map.put("vclN", zjVehicle.getVclN());
        map.put("vco", "2"); //车牌号中间无空格
        map.put("timeNearby", "72");
        map.put("qryBtm", zjVehicle.getQryBtm());
        map.put("qryEtm", zjVehicle.getQryEtm());
        String mapCode = "routerPath_" + MD5Utils.md5(zjVehicle.getVclN() + zjVehicle.getVnos() + zjVehicle.getQryBtm() + zjVehicle.getQryEtm()); // 字符串通过 MD5 进行加密, 作为存入 reids 的 key 值
        // 通过查询 redis 中是否存在该键值对判断是否调用api
        JsonNode jsonNode = null;

        // 返回的json对象
        JSONObject resultJson = new JSONObject();
        if (redisService.hasKey(mapCode)) { // redis 中存在, 不发请求, 直接从 redis 返回结果
            try {
                resultJson = redisService.getCacheObject(mapCode);
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }

        } else { // redis 中不存在, 调api, 并根据请求结果的状态码(1001表示服务执行成功)判断请求结果是否存redis: 1001-存, 非1001-不存
            try {
                DataExchangeService des = new DataExchangeService(5000, 8000);
                // 通过https方式调用!此方法内部会使用私钥生成签名参数 sign,私钥不会发送
                String zJres = des.postHttps(url + "/routerPath", map);
                String status = JSONObject.parseObject(zJres).getString("status");

                // 根据请求结果的状态码判断是否存redis
                if ("1001".equals(status)) {
                    JSONObject jsonObject = JSONObject.parseObject(zJres);
                    String mileage = jsonObject.getJSONObject("result").getString("mileage");
                    resultJson.put("mileage", mileage);




                    // 轨迹记录
                    JSONArray trackArrays = jsonObject.getJSONObject("result").getJSONArray("trackArray"); // 轨迹列表
                    List<TrackInfo> trackInfos = trackArrays.toJavaList(TrackInfo.class);

                    trackInfos.stream()
                            .map(trackInfo -> {
                                // 对 gtm 列的值进行转换
                                if (trackInfo.getGtm() != null && trackInfo.getGtm().length() > 11) {
                                    String newGtm = trackInfo.getGtm().replaceAll("/", "").substring(0, 12);
                                    trackInfo.setNewGtm(DateUtils.roundToNearest25810(Long.valueOf(newGtm)));
                                    ;
                                }
                                return trackInfo;
                            })
                            .collect(Collectors.toList());
//去重


                    // 使用流进行去重操作，根据 gtm 属性进行分组，然后取每组的第一个元素
                    List<TrackInfo> distinctAndSortedTrackInfos = trackInfos.stream()
                            .collect(Collectors.toMap(TrackInfo::getNewGtm, trackInfo -> trackInfo, (existing, replacement) -> existing))
                            .values()
                            .stream()
                            .sorted(Comparator.comparing(TrackInfo::getNewGtm)) // 按照 getNewGtm 属性升序排序
                            .collect(Collectors.toList());


                    List<Double[]> paths = new ArrayList<>();
                    List<Long> pathTimes = new ArrayList<>();
                    for (TrackInfo trackInfo : distinctAndSortedTrackInfos) {
                        CoordinateConverter.GPS gps = CoordinateConverter.gps84_To_Gcj02(trackInfo.getLat() / 600000.0, trackInfo.getLon() / 600000.0);

                        Double[] cood = {CoordinateConverter.formatDouble(gps.getWgLon()), CoordinateConverter.formatDouble(gps.getWgLat())};
                        paths.add(cood);
                        pathTimes.add(trackInfo.getNewGtm());

                    }
                    JSONObject trackInfoJson = new JSONObject();

                    trackInfoJson.put("path", paths);
                    trackInfoJson.put("pathTime", pathTimes);
                    resultJson.put("trackInfos", trackInfoJson);

                    // 返回结果中存入起始坐标和目的地坐标

                    resultJson.put("startPoint", paths.get(0));
                    resultJson.put("endPoint", paths.get(paths.size() - 1));
                    Coordinate startPosition = new Coordinate("1", String.valueOf(paths.get(0)[0]), String.valueOf(paths.get(0)[1]));
                    Coordinate endPosition = new Coordinate("1", String.valueOf( paths.get(paths.size() - 1)[0]), String.valueOf(paths.get(paths.size() - 1)[1]));
                    String startPositionAjaxResult = getDecodeAddress(startPosition);
                    String endPositionAjaxResult = getDecodeAddress(endPosition);

                    // Extract the "des" value in one step
                    String startPositionDesValue = JSONObject.parseObject(startPositionAjaxResult)
                            .getJSONObject("result")
                            .getString("des");

                    String endPositionDesValue = JSONObject.parseObject(endPositionAjaxResult)
                            .getJSONObject("result")
                            .getString("des");




                    JSONArray parkArray = jsonObject.getJSONObject("result").getJSONArray("parkArray"); // 停车列表
                    // 停车列表经纬度转换
                    JSONArray parkArrays = new JSONArray();
                    MapLabel startjo = new MapLabel();
                    startjo.setPosition(new Double[]{paths.get(0)[0],  paths.get(0)[1]});
                    startjo.setParkAdr(startPositionDesValue );
                    startjo.setParkMins(0);
                    startjo.setIndex(-1);
                    startjo.setAddr(startjo.getAddr());
                    parkArrays.add( startjo);

                    for (int i = 0; i < parkArray.size(); i++) {
                        JSONObject parseObject1 = (JSONObject) JSON.toJSON(parkArray.get(i));
                        Double parkLon = Integer.valueOf(parseObject1.getString("parkLon")) / 600000.0;
                        Double parkLat = Integer.valueOf(parseObject1.getString("parkLat")) / 600000.0;
                        CoordinateConverter.GPS gps = CoordinateConverter.gps84_To_Gcj02(parkLat, parkLon);

                        MapLabel jo = new MapLabel();

                        jo.setParkMins(Integer.valueOf(String.valueOf(parseObject1.get("parkMins"))));
//这里控制 停车时间
                        if (jo.getParkMins() > 29) {
                            Double[] cood = {CoordinateConverter.formatDouble(gps.getWgLon()), CoordinateConverter.formatDouble(gps.getWgLat())};
                            jo.setPosition(cood);
                            jo.setParkAdr(String.valueOf(parseObject1.get("parkAdr")));
                            jo.setLabel(null);
                            jo.setAddr(jo.getAddr());
                            jo.setIndex(0);
                            parkArrays.add(jo);
                        }

                    }

                    MapLabel endjo = new MapLabel();
                    endjo.setPosition( new Double[] {paths.get(paths.size() - 1)[0], paths.get(paths.size() - 1)[1]});
                    endjo.setParkAdr(endPositionDesValue );
                    endjo.setParkMins(0);
                    endjo.setIndex(1);
                    parkArrays.add( endjo);
                    resultJson.put("parkArrays", parkArrays);


                    redisService.setCacheObject(mapCode, resultJson);// 请求结果存redis

                }
                if ("1011".equals(status)) {
                    return AjaxResult.error("未加入白名单");
                }
                if ("1006".equals(status)) {
                    return AjaxResult.error(501, zjVehicle.getVclN() + ": 数据未入网");
                } else if ("1001".equals(status)) {
                    jsonNode = objectMapper.readTree(resultJson.toJSONString());
                    return success(jsonNode);
//                    return AjaxResult.success(zJres);
                } else {
                    return AjaxResult.error(501, zJres);
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        try {
            //字符串转为 json 将JSON字符串解析为JsonNode对象
            jsonNode = objectMapper.readTree(resultJson.toJSONString());
        } catch (Exception e) {
            e.printStackTrace();
        }

        return success(jsonNode);
    }

    public String getDecodeAddress(Coordinate coordinate) {
        String jsonRes = "";
        Map<String, String> map = new HashMap<String, String>(3);
        map.put("cid", clientId);
        map.put("srt", srt);
        map.put("type", coordinate.getType());
        map.put("lon", coordinate.getLon());
        map.put("lat", coordinate.getLat());
        JsonNode jsonNode = null;
        String mapCode = "decodeAddress_" + MD5Utils.md5(coordinate.getType() + coordinate.getLon() + coordinate.getLat()); // 字符串通过 MD5 进行加密, 作为存入 reids 的 key 值
        // 通过查询 redis 中是否存在该键值对判断是否调用api
        if (redisService.hasKey(mapCode)) {
            jsonRes = (String) redisService.getCacheObject(mapCode);
            return jsonRes;
        } else {
            DataExchangeService des = null;
            try {
                des = new DataExchangeService(5000, 8000);
                // 通过https方式调用!此方法内部会使用私钥生成签名参数 sign,私钥不会发送
                String res = des.postHttps(url + "/decodeAddress", map);
                String status = JSONObject.parseObject(res).getString("status");
                // 根据请求结果的状态码判断是否存redis
                System.out.println(status + " " + "1001".equals(status));
                if ("1001".equals(status)) {
                    redisService.setCacheObject(mapCode, res);
                }
                return  res;
            } catch (Exception e) {
                System.out.println(e);
            }
            return jsonRes;
        }

    }

    @ApiOperation("逆地理解析服务")
    @PostMapping("/decodeAddress")
    public AjaxResult decodeAddress(@RequestBody Coordinate coordinate) {
        Map<String, String> map = new HashMap<String, String>(3);
        map.put("cid", clientId);
        map.put("srt", srt);
        map.put("type", coordinate.getType());
        map.put("lon", coordinate.getLon());
        map.put("lat", coordinate.getLat());
        JsonNode jsonNode = null;
        String mapCode = "decodeAddress_" + MD5Utils.md5(coordinate.getType() + coordinate.getLon() + coordinate.getLat()); // 字符串通过 MD5 进行加密, 作为存入 reids 的 key 值
        // 通过查询 redis 中是否存在该键值对判断是否调用api
        if (redisService.hasKey(mapCode)) {
            String jsonRes = (String) redisService.getCacheObject(mapCode);
            // 将JSON字符串解析为JsonNode对象
            try {
                jsonNode = objectMapper.readTree(jsonRes);
            } catch (JsonProcessingException e) {
                System.out.println(e);
            }
        } else {
            DataExchangeService des = null;
            try {
                des = new DataExchangeService(5000, 8000);
                // 通过https方式调用!此方法内部会使用私钥生成签名参数 sign,私钥不会发送
                String res = des.postHttps(url + "/decodeAddress", map);
                String status = JSONObject.parseObject(res).getString("status");
                // 根据请求结果的状态码判断是否存redis
                System.out.println(status + " " + "1001".equals(status));
                if ("1001".equals(status)) {
                    redisService.setCacheObject(mapCode, res);
                }

                redisService.setCacheObject(mapCode, res);// 请求结果存redis
                String jsonRes = (String) redisService.getCacheObject(mapCode);
                // 将JSON字符串解析为JsonNode对象
                jsonNode = objectMapper.readTree(jsonRes);
            } catch (Exception e) {
                System.out.println(e);
            }

        }
        return success(jsonNode);
    }


    /**
     * 运输节点服务 接口测试
     *
     * @param vehicleNo
     * @param vnos
     * @return 返回的假数据
     */
    @ApiOperation("运输节点服务测试")
    @PostMapping("/transTimeManageV3Test")
    public AjaxResult transTimeManageV3Test(@RequestParam(value = "vehicleNo", required = true, defaultValue = "陕YH0009") String vehicleNo, @RequestParam String vnos) {
        Map<String, String> map = new HashMap<String, String>(3);
        map.put("cid", clientId);
        //私钥用于 SDK 生成签名，不会在请求中传输
        map.put("srt", srt);
        map.put("vnos", vehicleNo + "_" + colorMap.get(vnos)); //车牌号中间无空格
//        map.put("vnos", "陕YH0009_1"); //车牌号中间无空格
        map.put("timeNearby", "240");
        JsonNode jsonNode = null;
        try {
            DataExchangeService des = new DataExchangeService(5000, 8000);
            // 通过https方式调用!此方法内部会使用私钥生成签名参数 sign,私钥不会发送
//            String res = des.postHttps(url + "/transTimeManageV3", map);
//            jsonNode = objectMapper.readTree(res);
            // 将JSON字符串解析为JsonNode对象
            String s = "{\"result\":{\"firstVcl\":{\"adr\":\"河南省洛阳市涧西区入口,西北方向,132.0 米\",\"city\":\" 洛 阳 市 \",\"country\":\" 涧西区\",\"drc\":\"0\",\"estimateArriveTime\":\"1661538106278\",\"lat\":\"20788210\",\"lon\":\"67406467\",\"mil\":\"91410.7\",\"offlineState\":true,\"offlineTime\":\"29\",\"province\":\" 河南省\",\"remainDistance\":\"1181.6\",\"runDistance\":\"0.0\",\"spd\":\"0.0\",\"status\":\"1001\",\"utc\":\"1661477671000\",\"vno\":\"豫 CG5239\"},\"others\":[{\"adr\":\"河北省唐山市滦南县井离庄 村 , 东 南 方 向 ,530.1 米 \",\"city\":\" 唐山市 \",\"country\":\" 滦南县\",\"drc\":\"0\",\"lat\":\"23616055\",\"lon\":\"71213647\",\"mil\":\"396632.1\",\"province\":\" 河北省 \",\"spd\":\"0.0\",\"status\":\"1001\",\"utc\":\"1661479441000\",\"vno\":\" 冀B2229U\"},{\"adr\":\"江西省南昌市南昌县富山一路东口 18 号中铁物流,东南方向,83.0 米\",\"city\":\" 南昌市 \",\"country\":\" 南昌县\",\"drc\":\"0\",\"lat\":\"17131345\",\"lon\":\"69540358\",\"mil\":\"44108.7\",\"province\":\" 江西省 \",\"spd\":\"0.0\",\"status\":\"1001\",\"utc\":\"1645969947000\",\"vno\":\" 赣AB0091\"},{\"adr\":\"\",\"city\":\"\",\"country\":\"\",\"drc\":\"\",\"lat\":\"\",\"lon\":\"\",\"mil\":\"\",\"province\":\"\",\"spd\":\"\",\"status\":\"1006\",\"utc\":\"\",\"vno\":\" 陕YH0009\"},{\"adr\":\"\",\"city\":\"\",\"country\":\"\",\"drc\":\"\",\"lat\":\"\",\"lon\":\"\",\"mil\":\"\",\"povince\":\"\",\"spd\":\"\",\"status\":\"1002\",\"utc\":\"\",\"vno\":\" 皖K3D8329\"}]},\"status\":1001}";
            redisTemplate.opsForValue().set("mapMsg", s);
            String sResult = s.replace(" ", "");
            jsonNode = objectMapper.readTree(sResult);
        } catch (Exception e) {
            System.out.println(e);
        }
//        return ResponseData.success(jsonNode);
        return success(jsonNode);
    }


    /**
     * 运输节点服务
     *
     * @param vehicleNo
     * @param vnos
     * @return
     */
    @ApiOperation("运输节点服务需要输入起始的位置 或者行政区划")
    @PostMapping("/transTimeManageV3")
    public AjaxResult transTimeManageV3(@RequestParam(value = "vehicleNo", required = true, defaultValue = "陕YH0009") String vehicleNo, @RequestParam String vnos) {
        Map<String, String> map = new HashMap<String, String>(3);
        map.put("cid", clientId);
        //私钥用于 SDK 生成签名，不会在请求中传输
        map.put("srt", srt);
        map.put("vnos", vehicleNo + "_" + colorMap.get(vnos)); //车牌号中间无空格
//        map.put("vnos", "陕YH0009_1"); //车牌号中间无空格
        map.put("timeNearby", "240");
        JsonNode jsonNode = null;
        try {
            DataExchangeService des = new DataExchangeService(5000, 8000);
            // 通过https方式调用!此方法内部会使用私钥生成签名参数 sign,私钥不会发送
            String res = des.postHttps(url + "/transTimeManageV3", map);
            // 将JSON字符串解析为JsonNode对象
            jsonNode = objectMapper.readTree(res);
        } catch (Exception e) {
            System.out.println(e);
        }
        return success(jsonNode);
    }


    /**
     * 必经地/禁行地管理服务
     *
     * @param vno
     * @param vnos
     * @return
     */
    @ApiOperation("必经地/禁行地管理服务")
    @PostMapping("/groundPasses")
    public AjaxResult groundPasses(@RequestParam(value = "vehicleNo", required = true, defaultValue = "陕YH0009") String vno, @RequestParam Color vnos) {
        Map<String, Integer> colorMap = ColorMapping.getColorMap();

        Map<String, String> map = new HashMap<String, String>(3);
        map.put("cid", clientId);
        map.put("srt", srt);

        map.put("vno", vno);
        map.put("vco", String.valueOf(colorMap.get(vnos.toString()))); //车牌号中间无空格

        map.put("timeNearby", "72");
        JsonNode jsonNode = null;
        try {
            DataExchangeService des = new DataExchangeService(5000, 8000);
            // 通过https方式调用!此方法内部会使用私钥生成签名参数 sign,私钥不会发送
            String res = des.postHttps(url + "/groundPasses", map);
            // 将JSON字符串解析为JsonNode对象
            jsonNode = objectMapper.readTree(res);

        } catch (Exception e) {
            System.out.println(e);
        }
        return success(jsonNode);
    }


    /**
     * 入网验证服务
     *
     * @param vclN
     * @param vnos
     * @return
     */
    @ApiOperation("入网验证服务")
    @PostMapping("/checkTruckExistV2")
    public AjaxResult checkTruckExistV2(@RequestParam(value = "vehicleNo", required = true, defaultValue = "黑AN8721") String vclN, @RequestParam Color vnos) {
        Map<String, Integer> colorMap = ColorMapping.getColorMap();

        Map<String, String> map = new HashMap<String, String>(3);
        map.put("cid", clientId);
        map.put("srt", srt);
        map.put("vclN", vclN + "_" + String.valueOf(colorMap.get(vnos.toString())));
        JsonNode jsonNode = null;
        try {
            DataExchangeService des = new DataExchangeService(5000, 8000);
            // 通过https方式调用!此方法内部会使用私钥生成签名参数 sign,私钥不会发送
            String res = des.postHttps(url + "/checkTruckExistV2", map);
            // 将JSON字符串解析为JsonNode对象
            jsonNode = objectMapper.readTree(res);
        } catch (Exception e) {
            System.out.println(e);
        }
        return success(jsonNode);
    }


    /**
     * 入网确认服务
     *
     * @param vclN
     * @param vnos
     * @return
     */
    @ApiOperation("入网确认服务")
    @PostMapping("/checkVehicleExistV2")
    public AjaxResult checkVehicleExistV2(@RequestParam(value = "vehicleNo", required = true, defaultValue = "黑AN8721") String vclN, @RequestParam Color vnos) {
        Map<String, Integer> colorMap = ColorMapping.getColorMap();

        Map<String, String> map = new HashMap<String, String>(3);
        map.put("cid", clientId);
        map.put("srt", srt);
//        map.put("vco", ); //车牌号中间无空格
        map.put("vclN", vclN + "_" + String.valueOf(colorMap.get(vnos.toString())));

        JsonNode jsonNode = null;
        try {
            DataExchangeService des = new DataExchangeService(5000, 8000);
            // 通过https方式调用!此方法内部会使用私钥生成签名参数 sign,私钥不会发送
            String res = des.postHttps(url + "/checkVehicleExistV2", map);
            // 将JSON字符串解析为JsonNode对象
            jsonNode = objectMapper.readTree(res);

        } catch (Exception e) {
            System.out.println(e);
        }
        return success(jsonNode);
    }

    @GetMapping("/urlParameter")
    @ApiOperation("中交插件地图 构造参数url")
    public AjaxResult urlParameter(SinoiovDto dto) {
        Map<String, String> map = new HashMap<String, String>(3);
        map.put("cid", clientId);
        //私钥用于 SDK 生成签名，不会在请求中传输
        map.put("srt", srt);
        map.put("type", dto.getType());
        if (StringUtils.isNotEmpty(dto.getVnos()) && dto.getVnos().contains("色")) {
            dto.setVco(dto.getVnos());
        }


        if (StringUtils.isNotEmpty(dto.getVclN())) {
            String pluginParams = "{\"vclN\":\"%s\",\"vco\":%s,\"qryBtm\":\"%s\",\"qryEtm\":\"%s\"}";
            String formattedString = String.format(pluginParams, dto.getVclN(), colorMap.get(dto.getVco()), dto.getQryBtm(), dto.getQryEtm());
            map.put("pluginParams", formattedString);
        }

        String pluginUrl = "https://openapi.sinoiov.cn/save/apis/pluginUrl";
        String res = null;
        try {
            DataExchangeService des = new DataExchangeService(5000, 8000);
            // 通过https方式调用!此方法内部会使用私钥生成签名参数 sign,私钥不会发送
            res = des.postHttps(pluginUrl, map);
        } catch (Exception e) {
            log.error("======请求中交接口失败======", e);
        }
        log.info("======请求中交返回参数======:{}", res);

        return success(res);
    }
}
